/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { BaseExplicitGraph } from '../core/graph/BaseExplicitGraph';
import { DVFGNode, StmtOrFormalParm } from './VFGNode';
import { CallGraph } from '../callgraph/model/CallGraph';
import { GraphPrinter } from '../save/GraphPrinter';
import { PrinterBuilder } from '../save/PrinterBuilder';
import { SparseBitVector } from '../utils/SparseBitVector';
import { DVFGEdge, VFGEdgeKind } from './VFGEdge';

/**
 * Direct value flow graph
 * Consist of stmt(node) and direct Def-Use edge
 * Is basic of VFG. And VFG is building on DVFG
 */
export class DVFG extends BaseExplicitGraph {
    private cg: CallGraph;
    private stmtOrParm2NodeMap: Map<StmtOrFormalParm, SparseBitVector>;
    constructor(cg: CallGraph) {
        super();
        this.cg = cg;
        this.stmtOrParm2NodeMap = new Map();
    }

    public getCG(): CallGraph {
        return this.cg;
    }

    public getGraphName(): string {
        return 'Direct-VFG';
    }

    public addDVFGNode(node: DVFGNode, stmtOrParm: StmtOrFormalParm) {
        this.addNode(node);
        let sbv = this.getVFGNodeIDByStmtOrFP(stmtOrParm) || new SparseBitVector();
        sbv.set(node.getID());
        this.stmtOrParm2NodeMap.set(stmtOrParm, sbv);
    }

    public getVFGNodeIDByStmtOrFP(sp: StmtOrFormalParm): SparseBitVector | undefined {
        return this.stmtOrParm2NodeMap.get(sp);
    }

    public addDVFGEdge(src: DVFGNode, dst: DVFGNode, kind: VFGEdgeKind = VFGEdgeKind.DirectIntra): boolean {
        let edge = new DVFGEdge(src, dst, kind);
        if (this.ifEdgeExisting(edge)) {
            return false;
        }

        src.addOutgoingEdge(edge);
        dst.addIncomingEdge(edge);

        return true;
    }

    public dump(name: string): void {
        let printer = new GraphPrinter<this>(this);
        PrinterBuilder.dump(printer, name);
    }
}
export { VFGEdgeKind };

